

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;

import javax.crypto.Cipher;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class RSADecrypter {
	
	/*public static void main(String[] args) {
		try {
			String data = "4c99b90a943f8ec0252694bc654ba51897cbadf153309b63301001dd1872f313479b89d826a0f7a53f132bbf287bed765322b391d2225d473862165cc2f1e616058f1f79c015c60ed526ba398cd3fe43073fb134f025a1871d8cbe7d75d380d7281121e76e0f20a8d82670718b1a818a805b324d4da79de464305cb310fc159c";
			String getPass = decryptPassword(data);
			System.out.println(getPass);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}*/
	
	//Call this function to decrypt the given password
	public static String decryptPassword(String password){
		String decryptedPassword = "";
		try {
			Security.addProvider(new BouncyCastleProvider());
			
			PublicKey publicKey =  readKeyFromFile("/home/kapila/WS-WORKSPACE/SynchronizationTester/src/public.key");
			PrivateKey privateKey = readKey("/home/kapila/WS-WORKSPACE/SynchronizationTester/src/private.key");
			
			String data = password;
			byte[] cipherData = hexStringToByteArray(data);
			//System.out.println(cipherData);
			
			
			 Cipher decipher = Cipher.getInstance("RSA", "BC");
			 decipher.init(Cipher.DECRYPT_MODE, privateKey); 
			 byte[] decrypted = decipher.doFinal(cipherData);
			 String decryptedData = new String(decrypted);
			 //System.out.println("grr:" + decryptedData);
			 //String decryptedData = decrypted.toString();
				
			 
			 StringBuffer dataBuffer = new StringBuffer(decryptedData.toString()).reverse();
			 decryptedPassword = new String(dataBuffer.toString());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return decryptedPassword;
	}
	
	public static byte[] hexStringToByteArray(String s) {
		int len = s.length();
		//System.out.println(len);
		byte[] data = new byte[len / 2];
		for (int i = 0; i < len; i += 2) {
			data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character
					.digit(s.charAt(i + 1), 16));
		}
		return data;
	}
	
	
	private static void saveToFile(String fileName, BigInteger mod,
			BigInteger exp) throws IOException {
		ObjectOutputStream oout = new ObjectOutputStream(
				new BufferedOutputStream(new FileOutputStream(fileName)));
		try {
			oout.writeObject(mod);
			oout.writeObject(exp);
		} catch (Exception e) {
			throw new IOException("Unexpected error", e);
		} finally {
			oout.close();
		}

	}

	private static void saveToFile(String fileName, BigInteger mod,
			BigInteger pubExp,BigInteger privExp,BigInteger primeP,BigInteger primeQ,BigInteger primeExpP,
			BigInteger primeExpQ,BigInteger crtCof) throws IOException {
		ObjectOutputStream oout = new ObjectOutputStream(
				new BufferedOutputStream(new FileOutputStream(fileName)));
		try {
			oout.writeObject(mod);
			oout.writeObject(pubExp);
			oout.writeObject(privExp);
			oout.writeObject(primeP);
			oout.writeObject(primeQ);
			oout.writeObject(primeExpP);
			oout.writeObject(primeExpQ);
			oout.writeObject(crtCof);
		} catch (Exception e) {
			throw new IOException("Unexpected error", e);
		} finally {
			oout.close();
		}

	}
	public static String getHexString(byte[] b) throws Exception {
		String result = "";
		for (int i = 0; i < b.length; i++) {
			result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
		}
		return result;
	}

	static PublicKey readKeyFromFile(String keyFileName) throws IOException {

		Security.addProvider(new BouncyCastleProvider());
		InputStream in = new FileInputStream(keyFileName);
		ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(
				in));
		try {
			BigInteger m = (BigInteger) oin.readObject();
			BigInteger e = (BigInteger) oin.readObject();
			RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
			KeyFactory fact = KeyFactory.getInstance("RSA","BC");
			PublicKey pubKey = fact.generatePublic(keySpec);
			return pubKey;
		} catch (Exception e) {
			throw new RuntimeException("Spurious serialisation error", e);
		} finally {
			oin.close();
		}
	}

	static PrivateKey readKey(String keyFileName) {
		PrivateKey privateKey = null;
		try {
			Security.addProvider(new BouncyCastleProvider());
			InputStream in = new FileInputStream(keyFileName);
			ObjectInputStream oin = new ObjectInputStream(
					new BufferedInputStream(in));
			BigInteger mod = (BigInteger) oin.readObject();
			BigInteger pubExp = (BigInteger) oin.readObject();
			BigInteger privExp = (BigInteger) oin.readObject();
			BigInteger primeP = (BigInteger) oin.readObject();
			BigInteger primeQ = (BigInteger) oin.readObject();
			BigInteger primeExpP = (BigInteger) oin.readObject();
			BigInteger primeExpQ = (BigInteger) oin.readObject();
			BigInteger crtCof = (BigInteger) oin.readObject();
			RSAPrivateKeySpec keySpec = new RSAPrivateCrtKeySpec(mod,pubExp,privExp,primeP,primeQ,primeExpP,primeExpQ,crtCof);
			KeyFactory fact = KeyFactory.getInstance("RSA", "BC");
			privateKey = fact.generatePrivate(keySpec);

		} catch (Exception e) {
			e.printStackTrace();
		}
		return privateKey;
	}

	public static void keyGeneration() {
		try {

			Security.addProvider(new BouncyCastleProvider());
			KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
			kpg.initialize(1024);
			KeyPair kp = kpg.genKeyPair();

			RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
			RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey)kp.getPrivate();

			
			saveToFile("public.key", publicKey.getModulus(), publicKey.getPublicExponent());
			saveToFile("private.key", privateKey.getModulus() ,privateKey.getPublicExponent(), 
					privateKey.getPrivateExponent(), privateKey.getPrimeP(),privateKey.getPrimeQ(),privateKey.getPrimeExponentP(),
					privateKey.getPrimeExponentQ(), privateKey.getCrtCoefficient());
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
